package com.tencent.basic.interceptor;

import com.tencent.basic.annotation.PreAuthorize;
import com.tencent.basic.jwt.JwtUtils;
import com.tencent.basic.jwt.LoginData;
import com.tencent.basic.jwt.Payload;
import com.tencent.basic.jwt.RsaUtils;
import com.tencent.user.domain.Logininfo;
import com.tencent.user.mapper.LogininfoMapper;
import io.jsonwebtoken.ExpiredJwtException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.security.PublicKey;
import java.util.List;

/**
 * 后端登录拦截器
 */
@Component // 实例化对象 - 可以使用@Autowird自动注入了
public class LoginInterceptor implements HandlerInterceptor {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private LogininfoMapper logininfoMapper;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 首先获取token 已经在axios的前端拦截器中设置到了请求头中
        String token = request.getHeader("token"); // 浏览器中获取token
        // 判断token - 有 - 代表登陆过
        if (token != null) {
            // 通过RsaUtils获取公钥 解密使用
            PublicKey publicKey = RsaUtils.getPublicKey(RsaUtils.class.getClassLoader().getResource("auth_rsa.pub").getFile());
            try {
                // 解析 jwtToken 如果过期了直接走catch
                Payload<LoginData> payload = JwtUtils.getInfoFromToken(token, publicKey, LoginData.class);

                if (payload != null) { // 有信息 - 没过期 - 重新设置过期时间

                    // 重置过期时间 - 或者重新获取所有菜单权限等 重置过期时间 效率极低
                    // 或者 将加密好的token串 放进redis储存等 - 百度有方法 这里没做
                    // 为了方便测试 我们就在登录的业务中 将过期时间设置的极长

                    Logininfo logininfo = payload.getLoginData().getLogininfo();
                    // 这里开始做菜单menu权限 和 资源(按钮)permission权限
                    // 先验证登录logininfo信息 通过type判断其是否是前台用户
                    if (logininfo.getType() == 1) {
                        // 1. type==1 前台用户 放行
                        return true;
                    }
                    // 2. 不为 1 就是后台管理员 校验权限
                    // 3. 判断当前接口上是否有@PreAuthorize注解
                    HandlerMethod handlerMethod = (HandlerMethod) handler; // 接受请求的接口 - 我们controller中的方法

                    // handlerMethod.getMethod().getName(); 这里看出HandleMethod到底是什么

                    PreAuthorize preAuth = handlerMethod.getMethodAnnotation(PreAuthorize.class);
                    // 3.1 没有 放行
                    if (preAuth == null) {
                        return true;
                    } else {
                        // 3.2 有 获取当前方法上@PreAuthorize注解的sn ->  通过handler - 获取@PreAuthorize - 获取sn
                        String sn = preAuth.sn();
                        // 4. 根据logininfo_id 获取当前logininfo对象的所有权限 - 即t_permission表中的 sn
                        List<String> sns = logininfoMapper.loadPermissionByLogininfoId(logininfo.getId());

                        if (sns.contains(sn)) {
                            // 5. 判断logininfo的 权限 中 是否有该注解sn对应的sn
                            // 5.1 包含该sn 有权限 放行
                            return true;
                        } else {
                            // 5.2 不包含 - 没有权限 - 拦截 - 响应错误信息 - 交给前端
                            // json对象 - application/json - 格式在tomcat - conf - web.xml中查看
                            response.setContentType("application/json;charset=UTF-8");
                            response.getWriter().println("{\"success\":false,\"message\":\"noPermission\"}");
                            return false;
                        }
                    }
                }

            } catch (ExpiredJwtException e) {
                e.printStackTrace();
                response.setContentType("application/json;charset=UTF-8");
                response.getWriter().println("{\"success\":false,\"message\":\"timeout\"}");
                return false;
            }

            // redis的
//// 首先获取token 已经在axios的前端拦截器中设置到了请求头中
//            String token = request.getHeader("token"); // 浏览器中获取token
//            // 判断token - 有 - 代表登陆过
//            if (token != null) {
//            // 有就从通过token从redis中获取登录信息 - logininfo对象
//            Object logininfoObj = redisTemplate.opsForValue().get(token);
//            if (logininfoObj != null) { // 有信息 - 没过期 - 重新设置过期时间
//                redisTemplate.opsForValue().set(token, logininfoObj, 30, TimeUnit.MINUTES);
//
//                // 这里开始做菜单menu权限 和 资源(按钮)permission权限
//                Logininfo logininfo = (Logininfo)logininfoObj;
//                // 先验证登录logininfo信息 通过type判断其是否是前台用户
//                if (logininfo.getType() == 1) {
//                    // 1. type==1 前台用户 放行
//                    return true;
//                }
//
//                // 2. 不为 1 就是后台管理员 校验权限
//                // 3. 判断当前接口上是否有@PreAuthorize注解
//                HandlerMethod handlerMethod = (HandlerMethod) handler; // 接受请求的接口 - 我们controller中的方法
//
//                // handlerMethod.getMethod().getName(); 这里看出HandleMethod到底是什么
//
//                PreAuthorize preAuth = handlerMethod.getMethodAnnotation(PreAuthorize.class);
//                // 3.1 没有 放行
//                if (preAuth == null) {
//                    return true;
//                } else {
//                    // 3.2 有 获取当前方法上@PreAuthorize注解的sn ->  通过handler - 获取@PreAuthorize - 获取sn
//                    String sn = preAuth.sn();
//                    // 4. 根据logininfo_id 获取当前logininfo对象的所有权限 - 即t_permission表中的 sn
//                    List<String> sns = logininfoMapper.loadPermissionByLogininfoId(logininfo.getId());
//
//                    if (sns.contains(sn)) {
//                        // 5. 判断logininfo的 权限 中 是否有该注解sn对应的sn
//                        // 5.1 包含该sn 有权限 放行
//                        return true;
//                    } else {
//                        // 5.2 不包含 - 没有权限 - 拦截 - 响应错误信息 - 交给前端
//                        // json对象 - application/json - 格式在tomcat - conf - web.xml中查看
//                        response.setContentType("application/json;charset=UTF-8");
//                        response.getWriter().println("{\"success\":false,\"message\":\"noPermission\"}");
//                        return false;
//                    }
//                }
//            }
        }

        // 没有 - 登录信息过期了 跳转登录页面
        // 判断token - 没有 - 代表没登录过 - 跳转登录页面
        // 后端没页面不能直接跳转 ∴前端跳转 -> 告诉前端 我们要响应一个json数据 编码集为UTF-8

        // json对象 - application/json - 格式在tomcat - conf - web.xml中查看
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().println("{\"success\":false,\"message\":\"noLogin\"}");
        return false;

        // 然后写配置类 → config包
    }
}
